package fr.gdi.android.news;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.extras.ColorDialog;

import fr.gdi.android.news.utils.CharsetDetector;
import fr.gdi.android.news.utils.Constants.ExtraTags;
import fr.gdi.android.news.utils.FeedUtils;
import fr.gdi.android.news.utils.IOUtils;
import fr.gdi.android.news.utils.PreferenceUtils;
import fr.gdi.android.news.utils.Utils;

public class AddFeedActivity extends Activity
{
    private static final String FIND_URL = "https://ajax.googleapis.com/ajax/services/feed/find?v=1.0&q=";
    private static final int PROMPT = 1001;
    
    private boolean showFeedUrls = false;
    
    final class Error
    {
        String msg;
    }
    
    private int feedColor = -1;
    
    
    private class SearchFeedTask extends AsyncTask<String, Void, Void>
    {
        private ProgressDialog postDialog;
        private List<FeedDescription> descs = new ArrayList<FeedDescription>();
        
        @Override
        protected void onPreExecute()
        {
            postDialog = ProgressDialog.show(AddFeedActivity.this, 
                    getText(R.string.searching_feeds_title), 
                    getText(R.string.searching_feeds_text), 
                    true,  
                    false);
        }
        
        @Override
        protected Void doInBackground(String... args)
        {
            String value = args[0];
            InputStream in = null;
            try
            {
                String url = FIND_URL + URLEncoder.encode(value, "UTF-8");
                HttpClient client = new DefaultHttpClient();
                HttpGet request = new HttpGet(url);
                HttpResponse response = client.execute(request);
                
                String json = "";
                
                in = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                StringBuilder str = new StringBuilder();
                String line = null;
                while((line = reader.readLine()) != null)
                {
                    str.append(line + "\n");
                }
                json = str.toString();
                
                JSONObject object = new JSONObject(json);
                if ( object.has("responseData") ) 
                {
                    object = object.getJSONObject("responseData");
                    if ( object.has("entries") ) 
                    {
                        JSONArray array = object.getJSONArray("entries");
                        for ( int u = 0, l = array.length(); u < l; u++ ) 
                        {
                            JSONObject o = array.getJSONObject(u);
                            String feedUrl = o.getString("url");
                            String feedTitle = Utils.stripTags(o.getString("title"));
                            FeedDescription d = new FeedDescription(feedTitle, feedUrl);
                            descs.add(d);
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                if ( in != null ) 
                {
                    try
                    {
                        in.close();
                    }
                    catch (IOException e)
                    {
                        //swallow
                    }                                    
                }
            }
            return null;
        }
        
        @Override
        protected void onPostExecute(Void result)
        {
            postDialog.dismiss();
            
            if ( descs.size() == 0 )
            {
                Utils.showWarning(AddFeedActivity.this, AddFeedActivity.this.getText(R.string.no_feed_found).toString());
            }
            else
            {
                showFoundFeeds(AddFeedActivity.this, descs, null);
            }
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        onNewIntent(getIntent());
    }
    
    @Override
    protected Dialog onCreateDialog(int id)
    {
        switch ( id ) {
            case PROMPT: 
                AlertDialog.Builder alert = new AlertDialog.Builder(this);
                
                alert.setTitle(R.string.search_feed);
                //alert.setMessage(R.string.search_feed_input);
                
                LayoutInflater inflater = getLayoutInflater();
                View view = inflater.inflate(R.layout.search_feeds_dialog, null);
                alert.setView(view);
                final EditText input = (EditText) view.findViewById(R.id.search_terms);
                final CheckBox showUrls = (CheckBox) view.findViewById(R.id.show_url_after_search);
                
                alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                     
                    public void onClick(DialogInterface dialog, int whichButton) {
                        String value = input.getText().toString();
                        
                        if ( TextUtils.isEmpty(value) ) 
                        {
                            Toast.makeText(AddFeedActivity.this, AddFeedActivity.this.getText(R.string.search_term_empty), Toast.LENGTH_SHORT).show();
                        }
                        else 
                        {
                            AddFeedActivity.this.showFeedUrls = showUrls.isChecked();
                            dialog.cancel();
                            new SearchFeedTask().execute(value);
                        }
                    }
                });
    
                alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        dialog.cancel();
                    }
                });

            return alert.create();
        }
        return super.onCreateDialog(id);
    }
    
    public void onNewIntent(final Intent intent)
    {
        setContentView(R.layout.news_add_feed);
        
        final int position = intent.getIntExtra(ExtraTags.TAG_POSITION, -1);
        final boolean editMode = position != -1;
        final Activity activity = this;

        final EditText nameEditor = (EditText) findViewById(R.id.feed_name);
        nameEditor.setEnabled(!editMode);
        
         final View v = findViewById(R.id.feed_color); 
         v.setOnClickListener(new View.OnClickListener() {
             @Override 
             public void onClick(final View v) { 
                 String feedName = nameEditor.getText().toString(); 
                 int c = Color.WHITE; 
                 if ( !TextUtils.isEmpty(feedName) ) { 
                     c = PreferenceUtils.getIntPreference(activity, PreferenceUtils.getHeadlineColorKey(feedName), c, null); 
                     ColorDialog dlg = new ColorDialog(activity, false, null, c, new com.android.extras.ColorPickListener() {
                                 public void onPick(Object tag, int color) {
                                     v.setBackgroundColor(color); 
                                     feedColor = color; 
                                 } 
                             },
                             R.drawable.wheel); 
                     dlg.show(); 
                 } 
                 else 
                 { 
                     Utils.showWarning(activity, activity.getString(R.string.enter_feed_before)); 
                 } 
             } 
             });
         
        final EditText urlEditor = (EditText) findViewById(R.id.feed_url);
        
        if (editMode)
        {
            String name = intent.getStringExtra(ExtraTags.TAG_NAME);
            nameEditor.setText(name);
            
            urlEditor.setText(intent.getStringExtra(ExtraTags.TAG_URL));
            urlEditor.requestFocus();
            
            v.setBackgroundColor(FeedUtils.getFeedColor(this, name)); 
        }
        
        final Button saveBtn = (Button) findViewById(R.id.save);
        saveBtn.setText(R.string.ok);
        saveBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v)
            {
                onSave(editMode, position, intent.getStringExtra(ExtraTags.TAG_FEEDS));
            }
        });
        
        final Button searchBtn = (Button) findViewById(R.id.search);
        searchBtn.setText(R.string.search);
        searchBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v)
            {
                //finish();
                showDialog(PROMPT);
            }
        });
        
        final Button lookupBtn = (Button) findViewById(R.id.lookup);
        final Button checkBtn = (Button) findViewById(R.id.check);
        
        final Activity context = this;
        
        checkBtn.setText(R.string.check);
        checkBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v)
            {
                // Utils.showInfo(activity,
                // "Please wait while the feed is loading...");
                
                final ProgressDialog dlg = ProgressDialog.show(context, "", context.getString(R.string.checking_feed), true);
                
                new AsyncTask<Object, Void, Error>() {
                    protected Error doInBackground(Object... objects)
                    {
                        try
                        {
                            String url = ((EditText) findViewById(R.id.feed_url)).getText().toString();
                            String name = ((EditText) findViewById(R.id.feed_name)).getText().toString();
                            FeedUtils.getMostRecentNews(AddFeedActivity.this, new FeedDescription(name, url), true);
                            return null;
                        }
                        catch (Exception e)
                        {
                            Error err = new Error();
                            err.msg = e.getMessage();
                            return err;
                        }
                    };
                    
                    protected void onPostExecute(Error result)
                    {
                        dlg.dismiss();
                        if (result != null)
                        {
                            Utils.showError(activity, context.getString(R.string.invalid_feed));
                        }
                        else
                        {
                            Utils.showSuccess(activity, context.getString(R.string.feed_succesfully_loaded));
                        }
                        
                    };
                    
                }.execute(new Object[0]);
            }
        });
        
        final List<String> knownFeedTypes = Arrays.asList(new String[] { "application/rss+xml", "application/atom+xml", "application/rss xml", "application/atom xml", });
        lookupBtn.setOnClickListener(new OnClickListener() {
            
            public void onClick(View v)
            {
                // Utils.showInfo(activity,
                // "Looking up feed... Please wait a little bit.");
                
                final ProgressDialog dlg = ProgressDialog.show(context, "", context.getString(R.string.looking_up_feeds), true);
                
                new AsyncTask<Object, Void, Error>() {
                    private List<FeedDescription> foundFeeds = new ArrayList<FeedDescription>();
                    
                    private String url;
                    
                    protected Error doInBackground(Object... objects)
                    {
                        try
                        {
                            this.url = ((EditText) findViewById(R.id.feed_url)).getText().toString();
                            if (!url.startsWith("http://") && !url.startsWith("https://"))
                            {
                                url = "http://" + url;
                            }
                            byte[] bytes = IOUtils.getRemoteURLBytes(url);
                            String s = new String(bytes, CharsetDetector.detectCharset(bytes).name());
                            Pattern LINK_PATTERN = Pattern.compile("<link[^>]+>", Pattern.CASE_INSENSITIVE);
                            Pattern LINK_TYPE_PATTERN = Pattern.compile("type=('|\")([^('|\")]*)('|\")", Pattern.CASE_INSENSITIVE);
                            Pattern LINK_HREF_PATTERN = Pattern.compile("href=('|\")([^('|\")]*)('|\")", Pattern.CASE_INSENSITIVE);
                            Pattern LINK_TITLE_PATTERN = Pattern.compile("title=('|\")([^('|\")]*)('|\")", Pattern.CASE_INSENSITIVE);
                            Matcher m = LINK_PATTERN.matcher(s);
                            while (m.find())
                            {
                                String g = m.group();
                                Matcher m2 = LINK_TYPE_PATTERN.matcher(g);
                                if (m2.find())
                                {
                                    String attr = m2.group();
                                    String type = attr.substring(6, attr.length() - 1);
                                    
                                    if (knownFeedTypes.contains(type))
                                    {
                                        FeedDescription desc = null;
                                        Matcher m3 = LINK_HREF_PATTERN.matcher(g);
                                        if (m3.find())
                                        {
                                            attr = m3.group();
                                            String href = attr.substring(6, attr.length() - 1);
                                            desc = new FeedDescription(null, href);
                                        }
                                        if (desc != null)
                                        {
                                            Matcher m4 = LINK_TITLE_PATTERN.matcher(g);
                                            if (m4.find())
                                            {
                                                attr = m4.group();
                                                String title = attr.substring(7, attr.length() - 1);
                                                desc.name = title;
                                            }
                                            foundFeeds.add(desc);
                                        }
                                    }
                                }
                                
                            }
                            
                            return null;
                        }
                        catch (Exception e)
                        {
                            Log.e(this.getClass().getName(), "Unable to load feed", e);
                            Error err = new Error();
                            err.msg = e.getMessage();
                            return err;
                        }
                    };
                    
                    protected void onPostExecute(Error result)
                    {
                        dlg.dismiss();
                        if (result != null)
                        {
                            Utils.showError(activity, context.getString(R.string.cannot_load_url));
                        }
                        else
                        {
                            if (foundFeeds.size() == 0)
                            {
                                Utils.showSuccess(activity, context.getString(R.string.no_feed_found));
                            }
                            else
                            {
                                showFoundFeeds(context, foundFeeds, url);
                            }
                        }
                    };
                    
                }.execute(new Object[0]);
            }
        });
        
        boolean hasText = !TextUtils.isEmpty(urlEditor.getText());
        checkBtn.setEnabled(hasText);
        lookupBtn.setEnabled(hasText);
        
        urlEditor.addTextChangedListener(new TextWatcher() {
            
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count)
            {
            }
            
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after)
            {
            }
            
            @Override
            public void afterTextChanged(Editable s)
            {
                boolean hasText = !TextUtils.isEmpty(urlEditor.getText());
                checkBtn.setEnabled(hasText);
                lookupBtn.setEnabled(hasText);
            }
        });
    }
    
    public void onSave(boolean editMode, int position, String f)
    {
        String name = ((EditText) findViewById(R.id.feed_name)).getText().toString();
        String url = ((EditText) findViewById(R.id.feed_url)).getText().toString();
        
        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(url))
        {
            String message = this.getString(R.string.add_feed_mandatory);
            showError(message);
            return;
        }
        
        List<FeedDescription> feeds = FeedUtils.fromCsvString(f);
        for (FeedDescription feed : feeds)
        {
            if (!editMode && TextUtils.equals(feed.name, name))
            {
                String message = this.getString(R.string.add_feed_name_already_exists);
                showError(message);
                return;
            }
            if (TextUtils.equals(feed.url, url) && !editMode && TextUtils.equals(feed.name, name))
            {
                String message = this.getString(R.string.add_feed_url_already_exists);
                showError(message);
                return;
            }
        }
        returnFeed(name.replaceAll(" : ", " - ").replaceAll(": ", " - "), url, editMode, position);
    }
    
    private void returnFeed(String name, String url, boolean editMode, int position)
    {
        Intent resultValue = new Intent();
        resultValue.putExtra(ExtraTags.TAG_NAME, name);
        resultValue.putExtra(ExtraTags.TAG_URL, url);
        resultValue.putExtra(ExtraTags.TAG_EDIT, editMode);
        resultValue.putExtra(ExtraTags.TAG_POSITION, position);
        resultValue.putExtra(ExtraTags.TAG_COLOR, feedColor);
        setResult(RESULT_OK, resultValue);
        finish();
    }
    
    private void showError(String message)
    {
        /*
        Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 15, 15);
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.show();
        */
        LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.toast_error_layout, null, false);
        
        ImageView image = (ImageView) layout.findViewById(R.id.image);
        image.setImageResource(R.drawable.warning);
        TextView text = (TextView) layout.findViewById(R.id.text);
        text.setText(message);
        
        Toast toast = new Toast(this);
        toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.setView(layout);
        toast.show();
    }

    private void showFoundFeeds(final Activity context, final List<FeedDescription> foundFeeds, final String inputUrl)
    {
        AlertDialog.Builder dialog = new AlertDialog.Builder(context);
        dialog.setTitle(String.format(context.getString(R.string.found_feeds, foundFeeds.size())));
        
        final String[] items = new String[foundFeeds.size()];
        for (int u = 0; u < items.length; u++)
        {
            FeedDescription fd = foundFeeds.get(u);
            items[u] = showFeedUrls || TextUtils.isEmpty(fd.name) ? fd.url : fd.name;
        }
        dialog.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                String newUrl = null;
                FeedDescription fd = foundFeeds.get(which);
                String feedText = fd.url;
                if (TextUtils.isEmpty(inputUrl) || feedText.startsWith("http://") || feedText.startsWith("https://"))
                {
                    newUrl = feedText;
                }
                else
                {
                    if (feedText.startsWith("/")) feedText = feedText.substring(1);
                    newUrl = inputUrl + (!inputUrl.endsWith("/") ? "/" : "") + feedText;
                }
                ((EditText) findViewById(R.id.feed_url)).setText(newUrl);
                if (!TextUtils.isEmpty(fd.name))
                {
                    String n = fd.name.replaceAll(" : ", " - ").replaceAll(": ", " - ");
                    ((EditText) findViewById(R.id.feed_name)).setText(n);
                }
                dialog.dismiss();
            }
        });
        
        dialog.setNegativeButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
            }
        });
        
        dialog.create().show();
    }
}
